/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frfilter.c                                         */
/*  NOTE      = 任务管理                                           */
/*  DATE      = 2014/11/10 by guojq                                */
/*******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#include <nids.h>

#include "frcomm.h"
#include "frame_cfg.h"
#include "frmem.h"
#include "frlog.h"
#include "frlist.h"
#include "frconfig.h"
#include "frsutl.h"
#include "frame_params.h"
#include "frame.h"
#include "frxml_parse.h"
#include "frstr.h"
#include "frdaq.h"

#include "frfilter.h"

#define FILTER_CFG_LINE     256
#define STRING_TCP      "tcp"
#define STRING_UDP      "udp"
#define STRING_ICMP     "icmp"
#define STRING_ANY      "any"

typedef struct __filter_info {
    int i_action;
    int i_accept;    //0:丢弃 1:允许
    u_int sip_start;
    u_int sip_end;
    u_int dip_start;
    u_int dip_end;
    u_short sport_start;
    u_short sport_end;
    u_short dport_start;
    u_short dport_end;
    u_short us_proto;
    unsigned char arr_mac[APM_MAC_SIZE];
    int i_cmd;   //0:add 1:clear
} filter_info;

FR_STATIC Frlist_header *g_p_st_filter_head = NULL;
FR_STATIC Frlist_header g_st_filter_head_cache;

FR_STATIC pthread_spinlock_t  g_spin_cache_lock;
FR_STATIC pthread_rwlock_t g_filter_rwlock;

extern int g_i_pcap_threads;
extern Frlist_header g_st_lst_head_dev;

/*******************************************************************************
*  FUNC     :  取得链表头
*  ARGS     :  void
*  RTN      :  Frlist_header
*  NOTE     :
*******************************************************************************/
Frlist_header *apm_get_filter_list(void)
{
    return g_p_st_filter_head;
}

/*******************************************************************************
*  FUNC     :  释放链表节点
*  ARGS     :  Frlist_node* node   需要释放的链表节点
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __filter_node_free(Frlist_node* node)
{
    filter_info *p_st_filter = NULL;

    if (node == NULL || node->data == NULL)
        return;
    p_st_filter = (filter_info *)node->data;
    frfree(p_st_filter);
    return;
}

/*******************************************************************************
*  FUNC     :  int转换成字符串协议
*  ARGS     :  i_proto  协议号(IPPROTO_TCP/IPPROTO_UDP/IPPROTO_ICMP)
*  RTN      :  tcp/udp/icmp
*              其他返回NULL
*  NOTE     :
*******************************************************************************/
FR_STATIC const char *__bpfs_int2protoc(int i_proto)
{
    switch (i_proto)
    {
        case IPPROTO_TCP:
            return STRING_TCP;
        case IPPROTO_UDP:
            return STRING_UDP;
        case IPPROTO_ICMP:
            return STRING_ICMP;
    }
    return NULL;
}

/*******************************************************************************
*  FUNC     :  int转换成字符串协议
*  ARGS     :  i_proto  协议号(IPPROTO_TCP/IPPROTO_UDP/IPPROTO_ICMP/FILTER_PROTO_ANY)
*  RTN      :  tcp/udp/icmp/any
*              其他返回unknown
*  NOTE     :
*******************************************************************************/
FR_STATIC const char *__apm_filter_int2proto(int i_proto)
{
    switch (i_proto)
    {
        case IPPROTO_TCP:
            return STRING_TCP;
        case IPPROTO_UDP:
            return STRING_UDP;
        case IPPROTO_ICMP:
            return STRING_ICMP;
        case FILTER_PROTO_ANY:
            return STRING_ANY;
        default:
            break;
    }

    return "unknown";
}

/*******************************************************************************
*  FUNC     :  格式化显示一条规则
*  ARGS     :  p_st_node             当前节点
*           :  p_outbuff             出力的内容
*           :  ui_buff_size          出力的最大长度
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
FR_STATIC void __filter_node_format(filter_info *p_st_filter, char *p_outbuff, unsigned int ui_buff_size)
{
    char arr_sip_start[20];
    char arr_sip_end[20];
    char arr_dip_start[20];
    char arr_dip_end[20];

    if (p_st_filter == NULL)
        return;
    
    snprintf(arr_sip_start, sizeof(arr_sip_start), "%s", int_ntoa(p_st_filter->sip_start));
    snprintf(arr_sip_end, sizeof(arr_sip_end), "%s", int_ntoa(p_st_filter->sip_end));
    snprintf(arr_dip_start, sizeof(arr_dip_start), "%s", int_ntoa(p_st_filter->dip_start));
    snprintf(arr_dip_end, sizeof(arr_dip_end), "%s", int_ntoa(p_st_filter->dip_end));
    
    snprintf(p_outbuff, ui_buff_size, "%d %s %s-%s %d-%d %s-%s %d-%d "FRMAC_FMT "\n"
           , p_st_filter->i_accept
           , __apm_filter_int2proto(p_st_filter->us_proto)
           , arr_sip_start, arr_sip_end
           , p_st_filter->sport_start, p_st_filter->sport_end
           , arr_dip_start, arr_dip_end
           , p_st_filter->dport_start, p_st_filter->dport_end
           , FRMAC_ARG(p_st_filter->arr_mac));
    return;
}

/*******************************************************************************
*  FUNC     :  添加一条filter规则到最后
*  ARGS     :  i_action             当前规则的操作(放行/丢弃)
*           :  i_accept             过滤规则动作 1=允许通过 0=丢弃
*           :  ip_start             源ip
*           :  ip_end               源ip
*           :  src_port             源端口
*           :  dst_port             目标端口
*           :  us_proto             协议
*           :  arr_mac              mac地址
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  要先做init
*******************************************************************************/
//int apm_add_filter(int i_action, int i_accept, unsigned char arr_mac[APM_MAC_SIZE], u_short us_proto
//                  , u_int ip_start, u_int ip_end
//                  , u_short port_start, u_short port_end)
//{
//    filter_info *p_st_filter = NULL;
//    Frlist_node* p_st_node = NULL;
//
//    p_st_filter = (filter_info *)frmalloc(sizeof(filter_info));
//    if (p_st_filter == NULL)
//    {
//        FRLOG_ERROR_DETAIL("frmalloc failed");
//        return FR_FAIL;
//    }
//
//    p_st_filter->i_action = i_action;
//    p_st_filter->i_accept = i_accept;
//    p_st_filter->ip_start = ip_start;
//    p_st_filter->ip_end = ip_end;
//    p_st_filter->port_start = port_start;
//    p_st_filter->port_end = port_end;
//    p_st_filter->us_proto = us_proto;
//    memcpy(p_st_filter->arr_mac, arr_mac, APM_MAC_SIZE);
//
//    p_st_node = frlist_node_create((void *)p_st_filter);
//    if (p_st_node == NULL)
//    {
//        FRLOG_ERROR_DETAIL("frlist_node_create failed");
//        frfree(p_st_filter);
//        return FR_FAIL;
//    }
//
//    pthread_rwlock_wrlock(&g_filter_rwlock);
//    frlist_add_tail(g_p_st_filter_head, p_st_node);
//    pthread_rwlock_unlock(&g_filter_rwlock);
//
//    return FR_SUCC;
//}

/*******************************************************************************
*  FUNC     :  删除所有存在的filter规则
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
void apm_filter_remove_all(void)
{
    pthread_rwlock_wrlock(&g_filter_rwlock);
    frlist_remove_all(g_p_st_filter_head, __filter_node_free);
    pthread_rwlock_unlock(&g_filter_rwlock);
}

/*******************************************************************************
*  FUNC     :  字符串协议转换成int
*  ARGS     :  p_proto          字符串协议
*  RTN      :  协议号(IPPROTO_TCP/IPPROTO_UDP/IPPROTO_ICMP/FILTER_PROTO_ANY)
*              -1   不支持的协议
*  NOTE     :
*******************************************************************************/
FR_STATIC int __apm_filter_proto2int(char *p_proto)
{
    if (strncasecmp(p_proto, STRING_TCP, strlen(STRING_TCP)) == 0)
        return IPPROTO_TCP;
    else if (strncasecmp(p_proto, STRING_UDP, strlen(STRING_UDP)) == 0)
        return IPPROTO_UDP;
    else if (strncasecmp(p_proto, STRING_ICMP, strlen(STRING_ICMP)) == 0)
        return IPPROTO_ICMP;
    else if (strncasecmp(p_proto, STRING_ANY, strlen(STRING_ANY)) == 0)
        return FILTER_PROTO_ANY;

    return -1;
}

/*******************************************************************************
*  FUNC     :  读一行的filter数据
*  ARGS     :  p_line               一行的数据
*           :  pp_filter_info          记录数据的结构体
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  pp_filter_info外面要释放
*******************************************************************************/
FR_STATIC int __apm_filter_readline(char *p_line, filter_info **pp_filter_info)
{
    filter_info *p_filter_info = NULL;
    char *p_start = p_line;
    char *p_end = NULL;
    char arr_ip[50], arr_proto[20];
    unsigned char arr_mac[APM_MAC_SIZE];
    int i_proto = 0;

    p_filter_info = (filter_info *) frmalloc(sizeof(filter_info));
    if (p_filter_info == NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc failed");
        return FR_FAIL;
    }

    memset(p_filter_info, 0, sizeof(filter_info));

    //accept
    p_end = strchr(p_start, ' ');
    if (p_end == NULL)
        goto err;

    p_filter_info->i_accept = atoi(p_start);
    p_start = p_end + 1;
    //proto
    p_end = strchr(p_start, ' ');
    if (p_end == NULL)
        goto err;

    snprintf(arr_proto, sizeof(arr_proto)> p_end - p_start+1 ? p_end - p_start+1 : sizeof(arr_proto), "%s", p_start);
    i_proto = __apm_filter_proto2int(arr_proto);
    if (i_proto == -1)
        goto err;
    p_filter_info->us_proto = (u_short)i_proto;

    p_start = p_end + 1;

    //sip
    p_end = strchr(p_start, ' ');
    if (p_end == NULL)
        goto err;

    snprintf(arr_ip, sizeof(arr_ip)> p_end - p_start+1 ? p_end - p_start+1 : sizeof(arr_ip), "%s", p_start);
    iptools_parse_iprange(arr_ip, &p_filter_info->sip_start, &p_filter_info->sip_end);
    p_start = p_end + 1;

    //sport
    iptools_parse_portrange(p_start, &p_filter_info->sport_start, &p_filter_info->sport_end);
    p_end = strchr(p_start, ' ');
    if (p_end == NULL)
    {
        *pp_filter_info = p_filter_info;
        return FR_SUCC;
    }
    p_start = p_end + 1;
    //dip
    p_end = strchr(p_start, ' ');
    if (p_end == NULL)
    {
        *pp_filter_info = p_filter_info;
        return FR_SUCC;
    }

    snprintf(arr_ip, sizeof(arr_ip)> p_end - p_start+1 ? p_end - p_start+1 : sizeof(arr_ip), "%s", p_start);
    iptools_parse_iprange(arr_ip, &p_filter_info->dip_start, &p_filter_info->dip_end);
    p_start = p_end + 1;

    //dport
    iptools_parse_portrange(p_start, &p_filter_info->dport_start, &p_filter_info->dport_end);
    p_end = strchr(p_start, ' ');
    if (p_end == NULL)
    {
        *pp_filter_info = p_filter_info;
        return FR_SUCC;
    }
    p_start = p_end + 1;
    //mac
    if (iptools_parse_mac(p_end+1, arr_mac, APM_MAC_SIZE))
        memcpy(p_filter_info->arr_mac, arr_mac, APM_MAC_SIZE);

    *pp_filter_info = p_filter_info;
    return FR_SUCC;

err:
    frfree(p_filter_info);
    return FR_FAIL;
}

struct filter_ip4_addr
{
    unsigned char a, b, c, d;
};

static struct filter_ip4_addr __dotted_quad_to_ip (char *dottedquad)
{
    struct filter_ip4_addr ip;
    int a, b, c, d;
    
    sscanf (dottedquad, "%d.%d.%d.%d", &a, &b, &c, &d);
    
    ip.a = a;
    ip.b = b;
    ip.c = c;
    ip.d = d;
    
    return ip;
}

/*******************************************************************************
*  FUNC     :  将ip地址段组合成bpf规则
*  ARGS     :  ui_ip_start              起始ip地址段
*           :  ui_ip_end                结束ip地址段
*           :  p_out                    bpf规则
*           :  i_out_size               bpf规则长度
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  
*******************************************************************************/
static int __bpf_ip(u_int ui_sip_start, u_int ui_sip_end
                  , u_int ui_dip_start, u_int ui_dip_end
                  , char *p_out, int i_out_size)
{
    int i_len = 0;

    if (p_out == NULL || i_out_size <= 0)
        return FR_FAIL;

    //正常逻辑,存在sip和dip
    if (ui_sip_start && ui_sip_end && ui_dip_start && ui_dip_end)
    {
        struct filter_ip4_addr st_sip_start;
        struct filter_ip4_addr st_sip_end;
        struct filter_ip4_addr st_dip_start;
        struct filter_ip4_addr st_dip_end;

        st_sip_start = __dotted_quad_to_ip(int_ntoa(ui_sip_start));
        st_sip_end = __dotted_quad_to_ip(int_ntoa(ui_sip_end));
        st_dip_start = __dotted_quad_to_ip(int_ntoa(ui_dip_start));
        st_dip_end = __dotted_quad_to_ip(int_ntoa(ui_dip_end));

        //ip[12:4]为源ip地址
        if (st_sip_start.a == st_sip_end.a)
            snprintf(p_out, i_out_size, "((ip[12] == %d and ", st_sip_start.a);
        else
            snprintf(p_out, i_out_size, "((ip[12] >= %d and ip[12] <= %d and ", st_sip_start.a, st_sip_end.a);

        i_len = strlen(p_out);
        if (st_sip_start.b == st_sip_end.b)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[13] == %d and ", st_sip_start.b);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[13] >= %d and ip[13] <= %d and ", st_sip_start.b, st_sip_end.b);

        i_len = strlen(p_out);
        if (st_sip_start.c == st_sip_end.c)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[14] == %d and ", st_sip_start.c);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[14] >= %d and ip[14] <= %d and ", st_sip_start.c, st_sip_end.c);

        i_len = strlen(p_out);
        if (st_sip_start.d == st_sip_end.d)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[15] == %d) ", st_sip_start.d);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[15] >= %d and ip[15] <= %d) ", st_sip_start.d, st_sip_end.d);

        i_len = strlen(p_out);
        //ip[16:4]为目的ip地址
        if (st_dip_start.a == st_dip_end.a)
            snprintf(p_out + i_len, i_out_size - i_len, "and (ip[16] == %d and ", st_dip_start.a);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "and (ip[16] >= %d and ip[16] <= %d and ", st_dip_start.a, st_dip_end.a);

        i_len = strlen(p_out);
        if (st_dip_start.b == st_dip_end.b)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[17] == %d and ", st_dip_start.b);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[17] >= %d and ip[17] <= %d and ", st_dip_start.b, st_dip_end.b);

        i_len = strlen(p_out);
        if (st_dip_start.c == st_dip_end.c)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[18] == %d and ", st_dip_start.c);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[18] >= %d and ip[18] <= %d and ", st_dip_start.c, st_dip_end.c);

        i_len = strlen(p_out);
        if (st_dip_start.d == st_dip_end.d)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[19] == %d)", st_dip_start.d);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[19] >= %d and ip[19] <= %d)", st_dip_start.d, st_dip_end.d);

        i_len = strlen(p_out);
        //反方向的链路
        if (st_dip_start.a == st_dip_end.a)
            snprintf(p_out + i_len, i_out_size - i_len, "or (ip[12] == %d and ", st_dip_start.a);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "or (ip[12] >= %d and ip[12] <= %d and ", st_dip_start.a, st_dip_end.a);

        i_len = strlen(p_out);
        if (st_dip_start.b == st_dip_end.b)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[13] == %d and ", st_dip_start.b);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[13] >= %d and ip[13] <= %d and ", st_dip_start.b, st_dip_end.b);

        i_len = strlen(p_out);
        if (st_dip_start.c == st_dip_end.c)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[14] == %d and ", st_dip_start.c);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[14] >= %d and ip[14] <= %d and ", st_dip_start.c, st_dip_end.c);

        i_len = strlen(p_out);
        if (st_dip_start.d == st_dip_end.d)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[15] == %d) ", st_dip_start.d);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[15] >= %d and ip[15] <= %d) ", st_dip_start.d, st_dip_end.d);

        i_len = strlen(p_out);
        if (st_sip_start.a == st_sip_end.a)
            snprintf(p_out + i_len, i_out_size - i_len, "and (ip[16] == %d and ", st_sip_start.a);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "and (ip[16] >= %d and ip[16] <= %d and ", st_sip_start.a, st_sip_end.a);

        i_len = strlen(p_out);

        if (st_sip_start.b == st_sip_end.b)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[17] == %d and ", st_sip_start.b);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[17] >= %d and ip[17] <= %d and ", st_sip_start.b, st_sip_end.b);

        i_len = strlen(p_out);
        if (st_sip_start.c == st_sip_end.c)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[18] == %d and ", st_sip_start.c);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[18] >= %d and ip[18] <= %d and ", st_sip_start.c, st_sip_end.c);

        i_len = strlen(p_out);
        if (st_sip_start.d == st_sip_end.d)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[19] == %d))", st_sip_start.d);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[19] >= %d and ip[19] <= %d))", st_sip_start.d, st_sip_end.d);

        return FR_SUCC;
    }

    //只有一个ip, 源ip或者目的ip
    {
        struct filter_ip4_addr st_ip_start;
        struct filter_ip4_addr st_ip_end;

        if (ui_sip_start)
        {
            st_ip_start = __dotted_quad_to_ip(int_ntoa(ui_sip_start));
            st_ip_end = __dotted_quad_to_ip(int_ntoa(ui_sip_end));
        }
        else
        {
            st_ip_start = __dotted_quad_to_ip(int_ntoa(ui_dip_start));
            st_ip_end = __dotted_quad_to_ip(int_ntoa(ui_dip_end));
        }
        //ip[12:4]为源ip地址
        if (st_ip_start.a == st_ip_end.a)
            snprintf(p_out, i_out_size, "((ip[12] == %d and ", st_ip_start.a);
        else
            snprintf(p_out, i_out_size, "((ip[12] >= %d and ip[12] <= %d and ", st_ip_start.a, st_ip_end.a);

        i_len = strlen(p_out);
        if (st_ip_start.b == st_ip_end.b)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[13] == %d and ", st_ip_start.b);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[13] >= %d and ip[13] <= %d and ", st_ip_start.b, st_ip_end.b);

        i_len = strlen(p_out);
        if (st_ip_start.c == st_ip_end.c)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[14] == %d and ", st_ip_start.c);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[14] >= %d and ip[14] <= %d and ", st_ip_start.c, st_ip_end.c);

        i_len = strlen(p_out);
        if (st_ip_start.d == st_ip_end.d)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[15] == %d) ", st_ip_start.d);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[15] >= %d and ip[15] <= %d) ", st_ip_start.d, st_ip_end.d);

        i_len = strlen(p_out);
        //ip[16:4]为目的ip地址
        if (st_ip_start.a == st_ip_end.a)
            snprintf(p_out + i_len, i_out_size - i_len, "or (ip[16] == %d and ", st_ip_start.a);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "or (ip[16] >= %d and ip[16] <= %d and ", st_ip_start.a, st_ip_end.a);

        i_len = strlen(p_out);
        if (st_ip_start.b == st_ip_end.b)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[17] == %d and ", st_ip_start.b);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[17] >= %d and ip[17] <= %d and ", st_ip_start.b, st_ip_end.b);

        i_len = strlen(p_out);
        if (st_ip_start.c == st_ip_end.c)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[18] == %d and ", st_ip_start.c);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[18] >= %d and ip[18] <= %d and ", st_ip_start.c, st_ip_end.c);

        i_len = strlen(p_out);
        if (st_ip_start.d == st_ip_end.d)
            snprintf(p_out + i_len, i_out_size - i_len, "ip[19] == %d))", st_ip_start.d);
        else
            snprintf(p_out + i_len, i_out_size - i_len, "ip[19] >= %d and ip[19] <= %d))", st_ip_start.d, st_ip_end.d);

    }

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  将过滤规则组合成bpf规则
*  ARGS     :  p_filter                 规则内容
*           :  i_default_action         默认规则(0:全部丢弃 1:全部允许)
*           :  i_vlan_flag              0:非vlan的规则(不需要加vlan) 1:vlan规则
*           :  p_st_bpf                 bpf规则
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  
*******************************************************************************/
static int __filter2bpf(filter_info *p_filter, int i_default_action, int *p_i_vlan_flag, Frstr *p_st_bpf)
{
    Frstr *p_st_bpf_tmp = NULL;
    char arr_ip[1024] = {'\0'};
    char arr_sport[50] = {'\0'};
    char arr_dport[50] = {'\0'};
    char arr_port[128] = {'\0'};
    const char *p_protoc = NULL;
    
    if (p_filter == NULL || p_st_bpf == NULL)
        return FR_FAIL;
    
    //只做和默认相反的规则
    if (p_filter->i_accept == i_default_action)
        return FR_SUCC;

    //port规则    
    if (p_filter->sport_start || p_filter->sport_end)
    {
        if (p_filter->sport_start == p_filter->sport_end)
            snprintf(arr_sport, sizeof(arr_sport), "port %d", p_filter->sport_start);
        else
            snprintf(arr_sport, sizeof(arr_sport), "portrange %d-%d", p_filter->sport_start, p_filter->sport_end);

        if (p_filter->dport_start || p_filter->dport_end)
        {
            if (p_filter->dport_start == p_filter->dport_end)
                snprintf(arr_dport, sizeof(arr_dport), "port %d", p_filter->dport_start);
            else
                snprintf(arr_dport, sizeof(arr_dport), "portrange %d-%d", p_filter->dport_start, p_filter->dport_end);
            snprintf(arr_port, sizeof(arr_port), "(%s or %s)", arr_sport, arr_dport);
        }
        else
            snprintf(arr_port, sizeof(arr_port), "%s", arr_sport);

    }
    //兼容之前的版本,只有port不区分源和目的
    else if (p_filter->dport_start || p_filter->dport_end)
    {
        if (p_filter->dport_start == p_filter->dport_end)
            snprintf(arr_port, sizeof(arr_port), "port %d", p_filter->dport_start);
        else
            snprintf(arr_port, sizeof(arr_port), "portrange %d-%d", p_filter->dport_start, p_filter->dport_end);
    }
    
    //ip规则
    if (p_filter->sip_start || p_filter->sip_end || p_filter->dip_start || p_filter->dip_end)
    {
        if (__bpf_ip(p_filter->sip_start, p_filter->sip_end
                   , p_filter->dip_start, p_filter->dip_end
                   , arr_ip, sizeof(arr_ip)) != FR_SUCC)
            return FR_FAIL;
    }
    
    p_st_bpf_tmp = frstr_new(1024);
    if (p_st_bpf_tmp == NULL)
        return FR_FAIL;
    
    //添加协议
    p_protoc = __bpfs_int2protoc(p_filter->us_proto);
    if (p_protoc)
        FRSTR_APPEND_STR(p_st_bpf_tmp, p_protoc);
    
    //添加拼好的ip规则
    if (p_st_bpf_tmp->p_str[0] != '\0' && arr_ip[0] != '\0')
        FRSTR_APPEND_STR(p_st_bpf_tmp, " and ");
    
    FRSTR_APPEND_STR(p_st_bpf_tmp, arr_ip);
    
    //添加拼好的端口规则
    if (p_st_bpf_tmp->p_str[0] != '\0' && arr_port[0] != '\0')
        FRSTR_APPEND_STR(p_st_bpf_tmp, " and ");
    
    FRSTR_APPEND_STR(p_st_bpf_tmp, arr_port);
    
    //第一条规则
    if (p_st_bpf->p_str[0] == '\0')
    {
        //默认为允许。只写丢弃的规则
        if (i_default_action == 1)
        {
            FRSTR_APPEND_STR(p_st_bpf, "!");
        }
        FRSTR_APPEND_STR(p_st_bpf, "(");
        //增加是否抓取vlan的判断
        if (*p_i_vlan_flag == 0 && i_default_action == 0)
        {
            FRSTR_APPEND_STR(p_st_bpf, "(vlan and ");
            FRSTR_APPEND_STR(p_st_bpf, p_st_bpf_tmp->p_str);
            FRSTR_APPEND_STR(p_st_bpf, ")");
        }
        else
            FRSTR_APPEND_STR(p_st_bpf, p_st_bpf_tmp->p_str);
        
        FRSTR_APPEND_STR(p_st_bpf, ")");
    }
    else
    {
        if (i_default_action == 0)
        {
            FRSTR_APPEND_STR(p_st_bpf, " or (");
        }
        else
        {
            FRSTR_APPEND_STR(p_st_bpf, " and !(");
        }
        
        //增加是否抓取vlan的判断
        if (*p_i_vlan_flag == 0 && i_default_action == 0)
        {
            FRSTR_APPEND_STR(p_st_bpf, "(vlan and ");
            FRSTR_APPEND_STR(p_st_bpf, p_st_bpf_tmp->p_str);
            FRSTR_APPEND_STR(p_st_bpf, ")");
            *p_i_vlan_flag = 1;
        }
        else
            FRSTR_APPEND_STR(p_st_bpf, p_st_bpf_tmp->p_str);

        FRSTR_APPEND_STR(p_st_bpf, ")");
    }
    frstr_free(&p_st_bpf_tmp);
    
    return FR_SUCC;
}

static int __check_default_filter(filter_info *p_filter, int *p_i_action)
{
    if (p_filter
      && p_filter->sip_start == 0 && p_filter->sip_end == 0
      && p_filter->dip_start == 0 && p_filter->dip_end == 0
      && p_filter->sport_start == 0 && p_filter->sport_end == 0
      && p_filter->dport_start == 0 && p_filter->dport_end == 0
      && p_filter->us_proto == 0)
    {
        *p_i_action = p_filter->i_accept;
        return FR_SUCC;
    }
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  把bpf规则设置到libnids中
*  ARGS     :  p_filter      规则内容
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  
*******************************************************************************/
int frpcap_filter_add(void *p_daq_hand, const char *p_filter)
{
    int i_ret = 0;
    
    if (p_filter == NULL)
        return FR_FAIL;
    
    i_ret = DAQ_SetFilter(p_daq_hand, p_filter);
    if(i_ret != DAQ_SUCCESS)
    {
        FRLOG_ERROR_DETAIL("nids pcap_filter=[%s], set error", p_filter);
        return FR_FAIL;
    }
    FRLOG_INFO("set nids pcap_filter=[%s] success", p_filter);
    
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  从配置文件中读取filter配置
*  ARGS     :
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  适用于第一次读配置文件，运行中更新配置文件
*******************************************************************************/
int apm_filter_load(void *p_daq_hand, char **pp_result)
{
    filter_info *p_filter_line = NULL;
    Frlist_header *p_head_tmp = NULL;
    Frlist_header *p_doc_xml_head = NULL;
    Frlist_node *p_st_node = NULL;
    Frvar_field *p_st_field_tmp = NULL;
    int i_success = 0;
    int i_default_action = 1, i_has_filter = 0;
    filter_info *p_filter_tmp = NULL;
    Frstr *p_st_bpf=NULL;
    char arr_result[512];
    int i_vlan_flag = 1;   //第一次1,不用加vlan
    char arr_rule[128];
    
    if (frxml_get_string_list(APM_CFG_FILENAME_APM, APM_CFG_FRAME_XPATH_FILTER, APM_CFG_FILTER_KEY_FILTER, &p_doc_xml_head) == FR_FAIL)
    {
        FRLOG_ERROR_DETAIL("file [%s] error", APM_CFG_FILENAME_APM);
        snprintf(arr_result, sizeof(arr_result), "file [%s] error", APM_CFG_FILENAME_APM);
        *pp_result = frstrdup(arr_result);
        return FR_FAIL;
    }

    p_head_tmp = frlist_create();
    if (p_head_tmp == NULL)
    {
        FRLOG_ERROR_DETAIL("frlist_create failed");
        *pp_result = frstrdup("frlist_create failed");
        goto err;
    }
    
    //把xml里面的文件记录到链表中，并找出默认的规则
    p_st_node = FRLIST_FIRST_NODE(p_doc_xml_head);
    while(p_st_node)
    {
        p_st_field_tmp = (Frvar_field *)FRLIST_GET_NODE_DATA(p_st_node);
        if (p_st_field_tmp)
        {
            //每条命令做一次
            if (__apm_filter_readline(p_st_field_tmp->field_value.p_value, &p_filter_line) == FR_SUCC)
            {
                if (__check_default_filter(p_filter_line, &i_default_action) == FR_SUCC)
                {
                    frfree(p_filter_line);
                    break;
                }
                else
                {
                    Frlist_node* p_st_new_node = frlist_node_create(p_filter_line);
                    if (p_st_new_node == NULL)
                    {
                        FRLOG_ERROR_DETAIL("frlist_node_create failed");
                        frfree(p_filter_line);
                        goto err;
                    }
                    frlist_add_tail(p_head_tmp, p_st_new_node);
                    i_success = 1;
                }
                i_has_filter = 1;
            }
        }
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }
    //只有默认规则/没有规则
    if (i_has_filter == 0 || i_success == 0)
    {
        if (i_default_action)
            frpcap_filter_add(p_daq_hand, "vlan or not vlan");
        else
            frpcap_filter_add(p_daq_hand, "not ip");
        frxml_free_list(&p_doc_xml_head);
        frlist_destroy(p_head_tmp, __filter_node_free);
        //清空之前的规则
        {
            Frlist_header *p_head_old = g_p_st_filter_head;

            pthread_rwlock_wrlock(&g_filter_rwlock);
            g_p_st_filter_head = NULL;
            pthread_rwlock_unlock(&g_filter_rwlock);
            frlist_destroy(p_head_old, __filter_node_free);
        }
        return FR_SUCC;
    }
    p_st_bpf = frstr_new(1024);
    if (p_st_bpf == NULL)
        goto err;
        
    //创建出对应的bpf规则
    //对应libpcap 1.4版本，先处理不是vlan的包
    p_st_node = FRLIST_FIRST_NODE(p_head_tmp);
    while(p_st_node)
    {
        p_filter_tmp = (filter_info *)FRLIST_GET_NODE_DATA(p_st_node);
        if (p_filter_tmp)
        {
            if (__filter2bpf(p_filter_tmp, i_default_action, &i_vlan_flag, p_st_bpf) != FR_SUCC)
            {
                __filter_node_format(p_filter_tmp, arr_rule, sizeof(arr_rule) -1);
                snprintf(arr_result, sizeof(arr_result), "filter bpf err, [%s]", arr_rule);
                *pp_result = frstrdup(arr_result);
                frstr_free(&p_st_bpf);
                goto err;
            }
        }
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }
    //对应libpcap 1.4版本，再处理vlan的包
    if (i_default_action == 0)
    {
        i_vlan_flag = 0;
        p_st_node = FRLIST_FIRST_NODE(p_head_tmp);
        while(p_st_node)
        {
            p_filter_tmp = (filter_info *)FRLIST_GET_NODE_DATA(p_st_node);
            if (p_filter_tmp)
            {
                if (__filter2bpf(p_filter_tmp, i_default_action, &i_vlan_flag, p_st_bpf) != FR_SUCC)
                {
                    __filter_node_format(p_filter_tmp, arr_rule, sizeof(arr_rule) -1);
                    snprintf(arr_result, sizeof(arr_result), "filter bpf err, [%s]", arr_rule);
                    *pp_result = frstrdup(arr_result);
                    frstr_free(&p_st_bpf);
                    goto err;
                }
            }
            p_st_node = FRLIST_NEXT_NODE(p_st_node);
        }
    }
    
    //只有默认规则的情况
    if (p_st_bpf->p_str[0] == '\0')
    {
        //只有一条默认丢弃的规则
        if (i_default_action == 0)
            FRSTR_APPEND_STR(p_st_bpf, "not ip");
        else
        {
            FRSTR_APPEND_STR(p_st_bpf, "vlan or not vlan");
        }
    }
    //将bpf规则设置到nids里
    if (frpcap_filter_add(p_daq_hand, p_st_bpf->p_str) != FR_SUCC)
    {
        *pp_result = frstrdup("filter set bpf err");
        frstr_free(&p_st_bpf);
        goto err;
    }
    
    frstr_free(&p_st_bpf);

    if (i_success == 1)
    {
        Frlist_header *p_head_old = g_p_st_filter_head;

        pthread_rwlock_wrlock(&g_filter_rwlock);
        g_p_st_filter_head = p_head_tmp;
        pthread_rwlock_unlock(&g_filter_rwlock);
        frlist_destroy(p_head_old, __filter_node_free);
    }
    else
    {
        Frlist_header *p_head_old = g_p_st_filter_head;
        
        pthread_rwlock_wrlock(&g_filter_rwlock);
        g_p_st_filter_head = NULL;
        pthread_rwlock_unlock(&g_filter_rwlock);
        frlist_destroy(p_head_old, __filter_node_free);
        frlist_destroy(p_head_tmp, __filter_node_free);
    }

    frxml_free_list(&p_doc_xml_head);
    return FR_SUCC;

err:
    frxml_free_list(&p_doc_xml_head);
    frlist_destroy(p_head_tmp, __filter_node_free);
    //出错之后清空filter的内容，以免连续出错
    frxml_del2doc_all_cont(APM_CFG_FILENAME_APM, APM_CFG_FRAME_XPATH_FILTER, APM_CFG_FILTER_KEY_FILTER);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  添加一条准备的规则
*  ARGS     :  i_action             当前规则的操作(放行/丢弃)
*           :  i_accept             过滤规则动作 1=允许通过 0=丢弃
*           :  arr_mac              mac地址
*           :  us_proto             协议
*           :  p_src_ip             源ip
*           :  p_dst_ip             目标ip
*           :  p_sport              源端口
*           :  p_dport              目标端口
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  
*******************************************************************************/
int apm_prepare_add(int i_action, int i_accept, const char *p_mac, u_short us_proto
              , const char *p_sip, const char *p_dip, const char *p_sport, const char *p_dport)
{
    Frlist_node *p_st_new = NULL;
    filter_info *p_st_info_tmp;
    
    p_st_info_tmp = (filter_info*) frmalloc(sizeof(filter_info));
    if (p_st_info_tmp == NULL)
        return FR_FAIL;
    
    memset(p_st_info_tmp, 0x00, sizeof(filter_info));
    
    iptools_parse_iprange(p_sip, &p_st_info_tmp->sip_start, &p_st_info_tmp->sip_end);
    iptools_parse_iprange(p_dip, &p_st_info_tmp->dip_start, &p_st_info_tmp->dip_end);
    iptools_parse_portrange(p_sport, &p_st_info_tmp->sport_start, &p_st_info_tmp->sport_end);
    iptools_parse_portrange(p_dport, &p_st_info_tmp->dport_start, &p_st_info_tmp->dport_end);
    
    p_st_info_tmp->i_action = i_action;
    p_st_info_tmp->i_accept = i_accept;
    p_st_info_tmp->us_proto = us_proto;
    if (p_mac)
        memcpy(p_st_info_tmp->arr_mac, p_mac, APM_MAC_SIZE);
    p_st_info_tmp->i_cmd = 0;

    pthread_spin_lock(&g_spin_cache_lock);
    
    p_st_new = frlist_node_create(p_st_info_tmp);
    if (p_st_new == NULL)
    {
        frfree(p_st_info_tmp);
        pthread_spin_unlock(&g_spin_cache_lock);
        return FR_FAIL;
    }
    frlist_add_tail(&g_st_filter_head_cache, p_st_new);
    pthread_spin_unlock(&g_spin_cache_lock);
    return FR_SUCC;
}

FR_STATIC int __apm_filter_do_command(filter_info *p_st_filter)
{
    char arr_cmd[256];
    int i_ret = 0;
    
    if (p_st_filter == NULL)
        return FR_FAIL;
        
    switch (p_st_filter->i_cmd)
    {
        //add
        case 0:
            __filter_node_format(p_st_filter, arr_cmd, sizeof(arr_cmd));
            i_ret = frxml_insert2doc_content(APM_CFG_FILENAME_APM, APM_CFG_FRAME_XPATH_FILTER, APM_CFG_FILTER_KEY_FILTER, arr_cmd);
            return i_ret;
        //clear
        case 1:
            i_ret = frxml_del2doc_all_cont(APM_CFG_FILENAME_APM, APM_CFG_FRAME_XPATH_FILTER, APM_CFG_FILTER_KEY_FILTER);
            return i_ret;
        default:
            return FR_FAIL;
    }
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  清空filter规则
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
int apm_filter_clear_all(char **pp_result)
{
    int i_ret = 0;

    //删除配置文件apm.xml所有的内容
    i_ret = frxml_del2doc_all_cont(APM_CFG_FILENAME_APM, APM_CFG_FRAME_XPATH_FILTER, APM_CFG_FILTER_KEY_FILTER);
    if (i_ret != FR_SUCC)
    {
        *pp_result = frstrdup("apm.xml analyse failed");
        return FR_FAIL;
    }

    //删除规则
    {
        Frlist_node *p_st_node = NULL;
        p_st_node = FRLIST_FIRST_NODE(&g_st_lst_head_dev);
        while(p_st_node)
        {
            Nids_handle *p_nids_handle = NULL;

            p_nids_handle = (Nids_handle *)FRLIST_GET_NODE_DATA(p_st_node);
            if (p_nids_handle == NULL || p_nids_handle->p_dev == NULL)
                break;
            frpcap_filter_add(p_nids_handle->p_daq_hand, "vlan and not vlan");
            p_st_node = FRLIST_NEXT_NODE(p_st_node);
        }
    }
    pthread_spin_lock(&g_spin_cache_lock);
    frlist_remove_all(g_p_st_filter_head, __filter_node_free);
    frlist_remove_all(&g_st_filter_head_cache, __filter_node_free);
    pthread_spin_unlock(&g_spin_cache_lock);
    FRLOG_INFO_DETAIL("filter clear all");

    return i_ret;
}

/*******************************************************************************
*  FUNC     :  提交命令
*  ARGS     :  
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
void apm_filter_commit(char **pp_result)
{
    Frlist_node *p_st_tmp = NULL;
    filter_info *p_st_filter_tmp = NULL;
    
    pthread_spin_lock(&g_spin_cache_lock);

    p_st_tmp = FRLIST_FIRST_NODE(&g_st_filter_head_cache);
    while(p_st_tmp)
    {
        p_st_filter_tmp = (filter_info*)FRLIST_GET_NODE_DATA(p_st_tmp);
        if (p_st_filter_tmp)
        {
            __apm_filter_do_command(p_st_filter_tmp);
        }
        p_st_tmp = FRLIST_NEXT_NODE(p_st_tmp);
    }
    frlist_remove_all(&g_st_filter_head_cache, __filter_node_free);
    pthread_spin_unlock(&g_spin_cache_lock);

    {
        Frlist_node *p_st_node = NULL;
        p_st_node = FRLIST_FIRST_NODE(&g_st_lst_head_dev);
        while(p_st_node)
        {
            Nids_handle *p_nids_handle = NULL;

            p_nids_handle = (Nids_handle *)FRLIST_GET_NODE_DATA(p_st_node);
            if (p_nids_handle == NULL || p_nids_handle->p_dev == NULL)
                break;
            apm_filter_load(p_nids_handle->p_daq_hand, pp_result);
            p_st_node = FRLIST_NEXT_NODE(p_st_node);
        }
    }
    
    return;
}

/*******************************************************************************
*  FUNC     :  回滚命令
*  ARGS     :  
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
void apm_filter_rollback(void)
{
    pthread_spin_lock(&g_spin_cache_lock);
    frlist_remove_all(&g_st_filter_head_cache, __filter_node_free);
    pthread_spin_unlock(&g_spin_cache_lock);
    
    return;
}

/*******************************************************************************
*  FUNC     :  格式化显示一条规则
*  ARGS     :  p_st_node             当前节点
*           :  p_outbuff             出力的内容
*           :  ui_buff_size          出力的最大长度
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
FR_STATIC void __filter_node_show(Frlist_node* p_st_node, char *p_outbuff, unsigned int ui_buff_size)
{
    filter_info *p_st_filter = NULL;
    char arr_sip_start[20];
    char arr_sip_end[20];
    char arr_dip_start[20];
    char arr_dip_end[20];

    if (p_st_node == NULL || p_st_node->data == NULL)
        return;
    p_st_filter = (filter_info *)p_st_node->data;
    
    snprintf(arr_sip_start, sizeof(arr_sip_start), "%s", int_ntoa(p_st_filter->sip_start));
    snprintf(arr_sip_end, sizeof(arr_sip_end), "%s", int_ntoa(p_st_filter->sip_end));
    snprintf(arr_dip_start, sizeof(arr_dip_start), "%s", int_ntoa(p_st_filter->dip_start));
    snprintf(arr_dip_end, sizeof(arr_dip_end), "%s", int_ntoa(p_st_filter->dip_end));
    
    snprintf(p_outbuff, ui_buff_size, "%s %s %s-%s %d-%d %s-%s %d-%d "FRMAC_FMT "\n"
           , p_st_filter->i_accept == 1? "accept" : "drop"
           , __apm_filter_int2proto(p_st_filter->us_proto)
           , arr_sip_start, arr_sip_end
           , p_st_filter->sport_start, p_st_filter->sport_end
           , arr_dip_start, arr_dip_end
           , p_st_filter->dport_start, p_st_filter->dport_end
           , FRMAC_ARG(p_st_filter->arr_mac));
    return;
}

/*******************************************************************************
*  FUNC     :  显示filter所有的内容
*  ARGS     :  pp_out       所有的内容
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  pp_out外面需要释放内存
*******************************************************************************/
int apm_filter_show(char **pp_out)
{
    char *p_out = (char *)frmalloc(1024);
    
    if (p_out == NULL)
        return FR_FAIL;
    
    memset(p_out, 0x00, 1024);

    pthread_rwlock_rdlock(&g_filter_rwlock);
    frlist_show(g_p_st_filter_head, p_out, 1024, __filter_node_show);
    pthread_rwlock_unlock(&g_filter_rwlock);
    
    if (*p_out == '\0')
    {
        snprintf(p_out, 1024, "\n");
        *pp_out = p_out;
        return FR_SUCC;
    }
        
    *pp_out = p_out;
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  filter模块初始化
*  ARGS     :  void
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :
*******************************************************************************/
int apm_filter_init(void)
{
    int i_ret = 0;

    i_ret = pthread_rwlock_init(&g_filter_rwlock, NULL);
    if (i_ret != 0)
    {
        FRLOG_ERROR_DETAIL("pthread_rwlock_init failed");
        return FR_FAIL;
    }

    g_p_st_filter_head = frlist_create();
    if (g_p_st_filter_head == NULL)
    {
        FRLOG_ERROR_DETAIL("frlist create failed");
        return FR_FAIL;
    }
    
    pthread_spin_init(&g_spin_cache_lock, 0);
    frlist_header_init(&g_st_filter_head_cache);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  filter模块退出
*  ARGS     :
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void apm_filter_destroy(void)
{
    apm_filter_remove_all();
    pthread_rwlock_destroy(&g_filter_rwlock);
    pthread_spin_destroy(&g_spin_cache_lock);
    frlist_destroy(g_p_st_filter_head, __filter_node_free);
    frlist_remove_all(&g_st_filter_head_cache, __filter_node_free);
}

/*******************************************************************************
*  FUNC     :  filter clear命令
*  ARGS     :
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
int apm_filter_clear(void)
{
    Frlist_node *p_st_new = NULL;
    filter_info *p_st_info_tmp;
    
    p_st_info_tmp = (filter_info *) frmalloc(sizeof(filter_info));
    if (p_st_info_tmp == NULL)
        return FR_FAIL;
    
    memset(p_st_info_tmp, 0x00, sizeof(filter_info));
    p_st_info_tmp->i_cmd = 1;

    pthread_spin_lock(&g_spin_cache_lock);
    
    p_st_new = frlist_node_create(p_st_info_tmp);
    if (p_st_new == NULL)
    {
        frfree(p_st_info_tmp);
        pthread_spin_unlock(&g_spin_cache_lock);
        return FR_FAIL;
    }
    frlist_add_tail(&g_st_filter_head_cache, p_st_new);
    pthread_spin_unlock(&g_spin_cache_lock);
    return FR_SUCC;
}
